// Copyright (C) Kumo inc. and its affiliates.
// Author: Jeff.li lijippy@163.com
// All rights reserved.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published
// by the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program.  If not, see <https://www.gnu.org/licenses/>.
//

#include <cantor/type/type_kind.h>
#include <turbo/container/flat_hash_map.h>
#include <turbo/log/logging.h>

namespace cantor {
    // Static variable intialization is not thread safe for non
    // constant-initialization, but scoped static initialization is thread safe.
    const turbo::flat_hash_map<std::string, pb::TypeKind> &get_string_type_map() {
        static const turbo::flat_hash_map<std::string, pb::TypeKind> kTypeStringMap{
            {"INT8", pb::TypeKind::TYPE_KIND_INT8},
            {"INT16", pb::TypeKind::TYPE_KIND_INT16},
            {"INT32", pb::TypeKind::TYPE_KIND_INT32},
            {"INT64", pb::TypeKind::TYPE_KIND_INT64},
            {"INT128", pb::TypeKind::TYPE_KIND_INT128},
            {"UINT8", pb::TypeKind::TYPE_KIND_UINT8},
            {"UINT16", pb::TypeKind::TYPE_KIND_UINT16},
            {"UINT32", pb::TypeKind::TYPE_KIND_UINT32},
            {"UINT64", pb::TypeKind::TYPE_KIND_UINT64},
            {"UINT128", pb::TypeKind::TYPE_KIND_UINT128},
            {"FP8", pb::TypeKind::TYPE_KIND_FP8},
            {"FP16", pb::TypeKind::TYPE_KIND_FP16},
            {"FP32", pb::TypeKind::TYPE_KIND_FP32},
            {"FP64", pb::TypeKind::TYPE_KIND_FP64},
            {"STRING", pb::TypeKind::TYPE_KIND_STRING},
            {"BINARY", pb::TypeKind::TYPE_KIND_BINARY},
            {"TIMESTAMP", pb::TypeKind::TYPE_KIND_TIMESTAMP},
            {"DURATION", pb::TypeKind::TYPE_KIND_DURATION},
            {"BOOLEAN", pb::TypeKind::TYPE_KIND_BOOLEAN},
            {"DATETIME", pb::TypeKind::TYPE_KIND_DATETIME},
            {"INTERVAL", pb::TypeKind::TYPE_KIND_INTERVAL},
            {"DECIMAL64", pb::TypeKind::TYPE_KIND_DECIMAL64},
            {"DECIMAL128", pb::TypeKind::TYPE_KIND_DECIMAL128},
            {"ENUM", pb::TypeKind::TYPE_KIND_ENUM},
            {"ARRAY", pb::TypeKind::TYPE_KIND_ARRAY},
            {"MAP", pb::TypeKind::TYPE_KIND_MAP},
            {"SET", pb::TypeKind::TYPE_KIND_SET},
            {"STRUCT", pb::TypeKind::TYPE_KIND_STRUCT},
            {"TUPLE", pb::TypeKind::TYPE_KIND_TUPLE},
            {"UNION", pb::TypeKind::TYPE_KIND_UNION},
            {"UDF", pb::TypeKind::TYPE_KIND_UDF},
            {"JSON", pb::TypeKind::TYPE_KIND_JSON},
            {"PROTO", pb::TypeKind::TYPE_KIND_PROTO}
        };

        return kTypeStringMap;
    }

    const turbo::flat_hash_map<pb::TypeKind, std::string> &get_type_string_map() {
        static const turbo::flat_hash_map<pb::TypeKind, std::string> kStringTypeMap{
            {pb::TypeKind::TYPE_KIND_INT8, "INT8"},
            {pb::TypeKind::TYPE_KIND_INT16, "INT16"},
            {pb::TypeKind::TYPE_KIND_INT32, "INT32"},
            {pb::TypeKind::TYPE_KIND_INT64, "INT64"},
            {pb::TypeKind::TYPE_KIND_INT128, "INT128"},
            {pb::TypeKind::TYPE_KIND_UINT8, "UINT8"},
            {pb::TypeKind::TYPE_KIND_UINT16, "UINT16"},
            {pb::TypeKind::TYPE_KIND_UINT32, "UINT32"},
            {pb::TypeKind::TYPE_KIND_UINT64, "UINT64"},
            {pb::TypeKind::TYPE_KIND_UINT128, "UINT128"},
            {pb::TypeKind::TYPE_KIND_FP8, "FP8"},
            {pb::TypeKind::TYPE_KIND_FP16, "FP16"},
            {pb::TypeKind::TYPE_KIND_FP32, "FP32"},
            {pb::TypeKind::TYPE_KIND_FP64, "FP64"},
            {pb::TypeKind::TYPE_KIND_STRING, "STRING"},
            {pb::TypeKind::TYPE_KIND_BINARY, "BINARY"},
            {pb::TypeKind::TYPE_KIND_TIMESTAMP, "TIMESTAMP"},
            {pb::TypeKind::TYPE_KIND_DURATION, "DURATION"},
            {pb::TypeKind::TYPE_KIND_BOOLEAN, "BOOLEAN"},
            {pb::TypeKind::TYPE_KIND_DATETIME, "DATETIME"},
            {pb::TypeKind::TYPE_KIND_INTERVAL, "INTERVAL"},
            {pb::TypeKind::TYPE_KIND_DECIMAL64, "DECIMAL64"},
            {pb::TypeKind::TYPE_KIND_DECIMAL128, "DECIMAL128"},
            {pb::TypeKind::TYPE_KIND_ENUM, "ENUM"},
            {pb::TypeKind::TYPE_KIND_ARRAY, "ARRAY"},
            {pb::TypeKind::TYPE_KIND_MAP, "MAP"},
            {pb::TypeKind::TYPE_KIND_SET, "SET"},
            {pb::TypeKind::TYPE_KIND_STRUCT, "STRUCT"},
            {pb::TypeKind::TYPE_KIND_TUPLE, "TUPLE"},
            {pb::TypeKind::TYPE_KIND_UNION, "UNION"},
            {pb::TypeKind::TYPE_KIND_UDF, "UDF"},
            {pb::TypeKind::TYPE_KIND_JSON, "JSON"},
            {pb::TypeKind::TYPE_KIND_PROTO, "PROTO"}
        };

        return kStringTypeMap;
    }

    pb::TypeKind map_name_to_type_kind(const std::string &name) {
        auto found = get_string_type_map().find(name);

        if (found == get_string_type_map().end()) {
            return pb::TypeKind::TYPE_KIND_NONE;
        }

        return found->second;
    }

    std::string map_type_kind_to_name(const pb::TypeKind &typeKind) {
        auto found = get_type_string_map().find(typeKind);

        if (found == get_type_string_map().end()) {
            return "NONE";
        }

        return found->second;
    }

    std::ostream &operator<<(std::ostream &os, const pb::TypeKind &kind) {
        os << map_type_kind_to_name(kind);
        return os;
    }
} // namespace cantor
